<?php

declare(strict_types=1);
/**
 * This file is part of Hyperf.
 *
 * @link     https://www.hyperf.io
 * @document https://hyperf.wiki
 * @contact  group@hyperf.io
 * @license  https://github.com/hyperf/hyperf/blob/master/LICENSE
 */

namespace App\Exception\Handler;

use App\Constants\ErrorCode;
use App\Exception\BusinessException;
use App\Helper\ResponseHelper;
use Hyperf\Contract\StdoutLoggerInterface;
use Hyperf\ExceptionHandler\ExceptionHandler;
use Hyperf\HttpMessage\Exception\HttpException;
use Hyperf\Validation\ValidationException;
use Psr\Http\Message\ResponseInterface;
use Throwable;
use function Hyperf\Config\config;

class AppExceptionHandler extends ExceptionHandler
{
    public function __construct(protected StdoutLoggerInterface $logger)
    {
    }

    public function handle(Throwable $throwable, ResponseInterface $response)
    {
        // 记录异常日志
        $this->logger->error(sprintf(
            '[%s] %s in %s:%s',
            get_class($throwable),
            $throwable->getMessage(),
            $throwable->getFile(),
            $throwable->getLine()
        ));
        $this->logger->error($throwable->getTraceAsString());

        // 停止异常向上传播
        $this->stopPropagation();

        // 根据异常类型返回不同的响应
        return match (true) {
            // 业务异常
            $throwable instanceof BusinessException => $this->handleBusinessException($throwable),
            
            // 验证异常
            $throwable instanceof ValidationException => $this->handleValidationException($throwable),
            
            // HTTP 异常
            $throwable instanceof HttpException => $this->handleHttpException($throwable),
            
            // 其他异常
            default => $this->handleDefaultException($throwable),
        };
    }

    public function isValid(Throwable $throwable): bool
    {
        return true;
    }

    /**
     * 处理业务异常
     */
    protected function handleBusinessException(BusinessException $exception): ResponseInterface
    {
        return ResponseHelper::fail(
            message: $exception->getMessage(),
            code: $exception->getCode() ?: ErrorCode::BAD_REQUEST,
            data: []
        );
    }

    /**
     * 处理验证异常
     */
    protected function handleValidationException(ValidationException $exception): ResponseInterface
    {
        $errors = $exception->validator->errors()->toArray();
        
        return ResponseHelper::validationError(
            errors: $errors,
            message: 'Validation Failed'
        );
    }

    /**
     * 处理 HTTP 异常
     */
    protected function handleHttpException(HttpException $exception): ResponseInterface
    {
        $statusCode = $exception->getStatusCode();
        $message = $exception->getMessage() ?: $this->getHttpErrorMessage($statusCode);

        return ResponseHelper::json(
            code: $statusCode,
            message: $message,
            data: [],
            httpCode: $statusCode
        );
    }

    /**
     * 处理默认异常
     */
    protected function handleDefaultException(Throwable $throwable): ResponseInterface
    {
        // 生产环境隐藏详细错误信息
        $isDev = config('app_env') === 'dev';
        
        $message = $isDev 
            ? $throwable->getMessage() 
            : 'Internal Server Error';

        $data = $isDev ? [
            'exception' => get_class($throwable),
            'file' => $throwable->getFile(),
            'line' => $throwable->getLine(),
            'trace' => explode("\n", $throwable->getTraceAsString()),
        ] : [];

        return ResponseHelper::json(
            code: ErrorCode::SERVER_ERROR,
            message: $message,
            data: $data,
            httpCode: 500
        );
    }

    /**
     * 获取 HTTP 错误信息
     */
    protected function getHttpErrorMessage(int $statusCode): string
    {
        return match ($statusCode) {
            400 => 'Bad Request',
            401 => 'Unauthorized',
            403 => 'Forbidden',
            404 => 'Not Found',
            405 => 'Method Not Allowed',
            422 => 'Unprocessable Entity',
            429 => 'Too Many Requests',
            500 => 'Internal Server Error',
            502 => 'Bad Gateway',
            503 => 'Service Unavailable',
            default => 'HTTP Error',
        };
    }
}
